package com.gradumate.client.gui;

import java.util.ArrayList;
import java.util.logging.Logger;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.gradumate.client.Element;
import com.gradumate.client.GraduMate;
import com.gradumate.client.service.GraduMateService;
import com.gradumate.client.service.GraduMateServiceAsync;
import com.gradumate.shared.Gebruiker;
import com.gradumate.shared.OpleidingPerFaculteitOverzicht;
import com.gradumate.shared.Toolbox;

/**
 * Klasse om handmatig een gebruiker toe te voegen aan de database
 * @author IJsbrand
 *
 */
public class GebruikerToevoegen {
	
	// AsyncService
	private GraduMateServiceAsync server = GWT.create(GraduMateService.class);

	// Logger
	private final Logger log = Logger.getLogger(GebruikerSelectie.class.getName());
	
	// Elementen die nodig zin
	private TextBox txtVoornaam, txtAchternaam, txtEmailAdres, txtStudentnummer, txtInschrijfjaar;
	private ListBox lstGebruikerType, lstFaculteit, lstIstituut, lstOpleiding, lstOpleidingSACL;
	private Label lblStudentnummer, lblFaculteit, lblInstituut, lblOpleiding, lblHeeftToegang, lblInschrijfjaar, lblOpleidingSACL, lblMailOntvangen;
	private CheckBox chkbxHeeftToegang, chkbxMailOntvangen;
	
	// Table elementen
	private FlexTable flxTable;
	int row;
	
	// Element voor diverse kant en klaar elementen
	private Element element = new Element();
	
	// Submit button
	private final Button btnSubmit = element.getButton("Opslaan", "Opslaan", "user_add.png");
	
	/**
	 * Methode die indien alles goed ingevuld is een gebruiker object sturen naar de server kant.
	 */
	public GebruikerToevoegen() {
		// Controleren er al een status word getoond, anders weghalen
		GraduMate.clearStatusMessages();
		
		// Header
		FlexTable flxHeader = new FlexTable();
		flxHeader.setWidget(0, 0, element.getHeaderLabel("Gebruiker toevoegen"));
		flxHeader.setWidget(1, 0, element.getLabel("Op deze pagina kan je een gebruiker toevoegen aan het systeem."));
		flxHeader.setWidget(2, 0, element.getLabel("Deze gebruikers worden gebruikt om de Sharepoint koppeling te emuleren."));
		
		// Table aanmaken + row reset
		row = 0;
		flxTable = new FlexTable();
		flxTable.setCellPadding(3);
		
		// Voornaam
		txtVoornaam = new TextBox();
		flxTable.setWidget(row, 0, element.getLabel("Voornaam:"));
		flxTable.setWidget(row, 1, txtVoornaam);
		row++;
	
		// Achternaam
		txtAchternaam = new TextBox();
		flxTable.setWidget(row, 0, element.getLabel("Achternaam:"));
		flxTable.setWidget(row, 1, txtAchternaam);
		row++;
		
		// Email
		txtEmailAdres = new TextBox();
		flxTable.setWidget(row, 0, element.getLabel("HU e-mailadres"));
		flxTable.setWidget(row, 1, txtEmailAdres);
		row++;
		
		// Gebruikertypen ophalen + Clickevent om bijbehorende accounts op te halen uit DS
		lstGebruikerType = element.getGebruikerTypeListBox();
		lstGebruikerType.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				// Welk type is bepaald>
				int type = Integer.parseInt(lstGebruikerType.getValue(lstGebruikerType.getSelectedIndex()));
				
				// Wanneer niet leeg en student
				if (type != 0 && type == Gebruiker.TYPE_STUDENT) {
					showStudentInvoerVelden(true);
					showFaculteit(true);
					showMailOntvangen(false);
				// Wanneer Afstudeercommissie/Studie advsieur
				} else if (type == Gebruiker.TYPE_AFSTUDEERCOMMISSIE_LID || type == Gebruiker.TYPE_AFSTUDEERCOMMISIE_VOORZITTER || type == Gebruiker.TYPE_STUDIE_ADVISEUR) {
					showStudentInvoerVelden(false);
					showFaculteit(true);
					showMailOntvangen(true);
				// Anders
				} else  { 
					showStudentInvoerVelden(false);
					showFaculteit(false);
					showMailOntvangen(false);
				}
			}
		});
		flxTable.setWidget(row, 0, element.getLabel("Gebruikertype"));
		flxTable.setWidget(row, 1, lstGebruikerType);
		row++;
		
		// Studentnummer, alleen zichtbaar wanneer de Gebruikergroep student is geselecteerd
		txtStudentnummer = new TextBox();
		txtStudentnummer.setVisible(false);
		lblStudentnummer = element.getLabel("Studentnummer");
		lblStudentnummer.setVisible(false);
		flxTable.setWidget(row, 0, lblStudentnummer);
		flxTable.setWidget(row, 1, txtStudentnummer);
		row++;
		
		// Inschrijfjaar, alleen zichtbaar voor student.
		txtInschrijfjaar = new TextBox();
		txtInschrijfjaar.setVisible(false);
		lblInschrijfjaar = element.getLabel("Inschrijf jaar");
		lblInschrijfjaar.setVisible(false);
		flxTable.setWidget(row, 0, lblInschrijfjaar);
		flxTable.setWidget(row, 1, txtInschrijfjaar);
		row++;
		
		// Faculteit, alleen zichtbaar wanneer de Gebruikergroep student is geselecteerd
		lstFaculteit = element.getListBoxFaculteiten();
		lstFaculteit.setVisible(false);
		lstFaculteit.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				// Controleren er al een status word getoond, anders weghalen
				GraduMate.clearStatusMessages();
							
				// Faculteit bepalen
				String faculteit = lstFaculteit.getValue(lstFaculteit.getSelectedIndex());
				// Is faculteit echt geselecteerd?
				boolean door = (faculteit != null && faculteit.length() > 0);
				// Instituut laten zien
				showInstituut(door);
				
				// Wanneer er een faculteit is gaan we door.
				if (door) {
					OpleidingPerFaculteitOverzicht opfo = new OpleidingPerFaculteitOverzicht();
					lstIstituut.clear();
					lstIstituut.addItem("Selecteer een instituut", "");
					for (String instituut : opfo.getInstitutenByFaculteit(faculteit)) {
						lstIstituut.addItem(instituut);
					}
				} else {
					// Alleen bij false moet de opleiding weggehaald worden
					showOpleiding(door);
					showOpleidingSACL(door);
				}
			}
		});
		lblFaculteit = element.getLabel("Faculteit");
		lblFaculteit.setVisible(false);
		flxTable.setWidget(row, 0, lblFaculteit);
		flxTable.setWidget(row, 1, lstFaculteit);
		row++;
		
		// Instuten
		lstIstituut = new ListBox();
		lstIstituut.setVisible(false);
		lstIstituut.addChangeHandler(new ChangeHandler() {
			@SuppressWarnings("deprecation")
			public void onChange(ChangeEvent e) {
				int type = Integer.parseInt(lstGebruikerType.getValue(lstGebruikerType.getSelectedIndex()));
				
				String instituut = lstIstituut.getValue(lstIstituut.getSelectedIndex());
				String faculteit = lstFaculteit.getValue(lstFaculteit.getSelectedIndex());
				
				// Mag alleen doorgaan wanneer instituut en faculteit niet leeg zijn.
				boolean door = ((instituut != null && instituut.length() > 0) && (faculteit != null && faculteit.length() > 0));
				OpleidingPerFaculteitOverzicht opfo = new OpleidingPerFaculteitOverzicht();
				
				if (door) {
					if (type != 0 && type == Gebruiker.TYPE_STUDENT) {
						showOpleiding(door);
						lstOpleiding.clear();
						lstOpleiding.addItem("Selecteer een opleiding", "");
						for (String opleiding : opfo.getOpleidingenByFaculteitAndInstituut(faculteit, instituut)) {
							lstOpleiding.addItem(opleiding);
						}
					} else if (type == Gebruiker.TYPE_AFSTUDEERCOMMISIE_VOORZITTER || type == Gebruiker.TYPE_AFSTUDEERCOMMISSIE_LID || type == Gebruiker.TYPE_STUDIE_ADVISEUR) {
						showOpleidingSACL(door);
						lstOpleidingSACL.setMultipleSelect(true);
						lstOpleidingSACL.clear();
						//lstOpleidingSACL.addItem("Selecteer een opleiding", "");
						for (String opleiding : opfo.getOpleidingenByFaculteitAndInstituut(faculteit, instituut)) {
							lstOpleidingSACL.addItem(opleiding);
						}
					}
				}
			}
		});
		lblInstituut = element.getLabel("Instituut");
		lblInstituut.setVisible(false);
		flxTable.setWidget(row, 0, lblInstituut);
		flxTable.setWidget(row, 1, lstIstituut);
		row++;
		
		// Opleiding, alleen zichtbaar wanneer de Gebruikergroep student is geselecteerd en er een instituut en faculteit is geslecteerd
		lstOpleiding = new ListBox();
		lstOpleiding.setVisible(false);
		lblOpleiding = element.getLabel("Opleiding");
		lblOpleiding.setVisible(false);
		flxTable.setWidget(row, 0, lblOpleiding);
		flxTable.setWidget(row, 1, lstOpleiding);
		row++;
		
		// Opleiding voor StudieAdviseur en AfstudeerCommisse
		lstOpleidingSACL = new ListBox(true);
		lstOpleidingSACL.setVisible(false);
		lblOpleidingSACL = element.getLabel("Opleiding");
		lblOpleidingSACL.setVisible(false);
		flxTable.setWidget(row, 0, lblOpleidingSACL);
		flxTable.setWidget(row, 1, lstOpleidingSACL);
		row++;
		
		// Toegang, alleen zichtbaar wanneer de Gebruikergroep student is geselecteerd
		chkbxHeeftToegang = new CheckBox();
		chkbxHeeftToegang.setVisible(false);
		lblHeeftToegang = element.getLabel("Heeft toegang");
		lblHeeftToegang.setVisible(false);
		flxTable.setWidget(row, 0, lblHeeftToegang);
		flxTable.setWidget(row, 1, chkbxHeeftToegang);
		row++;
		
		// Mailtontvangen, alleen zichtbaar voor studieadviseurs en commissieleden
		chkbxMailOntvangen = new CheckBox();
		chkbxMailOntvangen.setVisible(false);
		lblMailOntvangen = element.getLabel("Wil je mail ontvangen?");
		lblMailOntvangen.setVisible(false);
		flxTable.setWidget(row, 0, lblMailOntvangen);
		flxTable.setWidget(row, 1, chkbxMailOntvangen);
		row++;
		
		// Submit button
		btnSubmit.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent ce) {
				setButtonLoadingImage(true);
				
				// Standaard variabelen ophalen
				String voornaam = txtVoornaam.getValue();
				String achternaam = txtAchternaam.getValue();
				String email = txtEmailAdres.getValue();
				final int type = Integer.parseInt(lstGebruikerType.getValue(lstGebruikerType.getSelectedIndex()));
				
				// Student variabelen initieeren
				int studentnummer = 0;
				int inschrijfjaar = 0;
				boolean heeftToegang = false;
				boolean mailOntvangen = false;
				
				// Student, StudieAdviseur en CommissieLid variabelen initeren
				String faculteit = null;
				String instituut = null;
				String opleiding = null;
				ArrayList<String> opleidingen = new ArrayList<String>();
								
				// Toolbox aanroepen voor Regex
				Toolbox tb = new Toolbox();
				String errorMsg = "";
				
				// Voornaam is leeg of voldoet niet aan de RegEx
				if (voornaam != null && !tb.NaamRegex(voornaam)) {
					errorMsg += "- Voornaam is niet/niet goed ingevoerd. \n";
				}
				
				// Achternaam is leeg of voldoet niet aan de RegEx
				if (achternaam != null && !tb.NaamRegex(achternaam)) {
					errorMsg += "- Achternaam is niet/niet goed ingevoerd. \n";
				}
				
				// TODO: Controle inbouwen voor emailadres controle
				
				// Er is geen type geselecteerd
				if (!(type > 0)) {
					errorMsg += "- Er is geen gebruikertype geselecteerd. \n";
				} 
				
				// Wanneer type Student, Afstudeercommissie of Studieadviseur
				if (type != 0 && type == Gebruiker.TYPE_STUDENT || type == Gebruiker.TYPE_AFSTUDEERCOMMISIE_VOORZITTER || type == Gebruiker.TYPE_AFSTUDEERCOMMISSIE_LID || type == Gebruiker.TYPE_STUDIE_ADVISEUR) {
					
					// Facutlteit en Instituut is er altijd 1
					faculteit = lstFaculteit.getValue(lstFaculteit.getSelectedIndex());
					instituut = lstIstituut.getValue(lstIstituut.getSelectedIndex());
					
					if (type == Gebruiker.TYPE_AFSTUDEERCOMMISSIE_LID || type == Gebruiker.TYPE_AFSTUDEERCOMMISIE_VOORZITTER || type == Gebruiker.TYPE_STUDIE_ADVISEUR) {	
						// Wil een Gebruiker van deze typen een mailtje ontvangen?
						mailOntvangen = chkbxMailOntvangen.getValue();
						
						// Hoeveel items zijn er?
						int items = lstOpleidingSACL.getItemCount();
						
						// Doorlopen en de opleidingen toevoegen.
						for (int i = 0; i != items; i++) {
							if (lstOpleidingSACL.isItemSelected(i)) {
								opleidingen.add(lstOpleidingSACL.getValue(i));
							}
						}
					} else {
						opleiding = lstOpleiding.getValue(lstOpleiding.getSelectedIndex());
					}
				}
				
				// Wanneer student, dan controleren op cluster, opleiding en studentnummer
				if (type != 0 && type == Gebruiker.TYPE_STUDENT) {	
					
					// Variabelen setten
					studentnummer = Integer.parseInt(txtStudentnummer.getValue());
					inschrijfjaar = Integer.parseInt(txtInschrijfjaar.getValue());
					heeftToegang = chkbxHeeftToegang.getValue();
					
					// TODO: Studentnummer controle toevoegen
					if (studentnummer == 0) {
						errorMsg += "- Voer een studentnummer in. \n";
					}
					
					// Inschrijfjaar is leeg
					if (inschrijfjaar == 0) {
						errorMsg += "- Voer een inschrijfjaar in. \n";
					}
					
					// Facutlteit is leeg
					if (faculteit == null) {
						errorMsg += "- Kies een faculteit. \n";
					}
					
					// Inistituut is leeg
					if (instituut == null) {
						errorMsg += "- Kies een instituut. \n";
					}
					
					// TODO:  && tb.NaamRegex(opleiding) regex
					if (opleiding == null) {
						errorMsg += "- Kies een opleiding \n";
					}
				}
				
				// Geen fout, dan door
				if (errorMsg.length() == 0) {
					
					// Gebruiker aanmaken
					final Gebruiker gebruiker = new Gebruiker();
					gebruiker.setVoornaam(voornaam);
					gebruiker.setAchternaam(achternaam);
					gebruiker.setGebruikerEmail(email);
					gebruiker.setType(type);
					
					// Wanneer student, overige attributen invullen.
					if (type != 0 && type == Gebruiker.TYPE_STUDENT || type == Gebruiker.TYPE_AFSTUDEERCOMMISIE_VOORZITTER || type == Gebruiker.TYPE_AFSTUDEERCOMMISSIE_LID || type == Gebruiker.TYPE_STUDIE_ADVISEUR) {
						
						// Faculteit en Instituut zetten
						gebruiker.setFaculteit(faculteit);
						gebruiker.setInstituut(instituut);
						
						// Wanneer het een student is moeten studentnumer, inschrijfjaar en heeftoegang worden geset
						if (type == Gebruiker.TYPE_STUDENT) {
							// Enkele opleiding toevoegen
							gebruiker.addOpleiding(opleiding);
							gebruiker.setStudentNummer(studentnummer);
							gebruiker.setInschrijfjaar(inschrijfjaar);
							gebruiker.setHeeftToegang(heeftToegang);
						} else {
							// Anders arraylist zetten
							gebruiker.setOpleiding(opleidingen);
							gebruiker.setMailOntvangen(mailOntvangen);
						}
					}
					
					// Service aanroepen.
					server.addGebruiker(gebruiker, type, new AsyncCallback<Boolean>() {
						
						public void onFailure(Throwable caught) {	
							setButtonLoadingImage(false);
							log.info("addGebruiker(" + gebruiker + ") | AsyncCallback " + caught.getMessage());
							GraduMate.addAsyncError();
						}
						
						public void onSuccess(Boolean result) {
							if (result) {
								// Resultaat weergeven
								GraduMate.addSuccessMsg("Gebruiker " + gebruiker.getVoornaam() + " is succesvol toegevoegd.");
								
								// Laad gifje uitzetten
								setButtonLoadingImage(false);
								
								// Submit button uitzetten zodat niet nog een keer de zelfde gebruiker word aangemaakt.
								btnSubmit.setEnabled(false);
							} else {
								setButtonLoadingImage(false);
								GraduMate.addErrorMsg("Er bestaat al een gebruiker met " + gebruiker.getGebruikerEmail() + " emailadres");
							}
						}
					});
				} else {
					setButtonLoadingImage(false);
					GraduMate.addErrorMsg("De gebruiker kon niet worden opgeslagen omdat sommige invoervelden niet goed ingevuld zijn. Pas onderstaande velden aan: \n\n" + errorMsg);
				}
			}
		});
		
		// Terug button.
		Button btnTerug = element.getButton("Terug", "Ga terug", "cancel.png");
		btnTerug.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent e) {
				new GebruikerSelectie();
			}
		});
		
		// Nog een gebruiker toevoegen
		Button btnNogEenToevoegen = element.getButton("Nog een toevoegen", "Nog een toevoegen", "user_add.png");
		btnNogEenToevoegen.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent e) {
				new GebruikerToevoegen();
			}
		});
		
		// FlexTable voor de buttons
		FlexTable flxButton = new FlexTable();
		
		// Buttons op het panel zetten
		flxButton.setWidget(0, 0, btnSubmit);
		flxButton.setWidget(0, 1, btnTerug);
		flxButton.setWidget(0, 2, btnNogEenToevoegen);
		
		// Loading gif weghalen
		GraduMate.setLoadingImage(false);
		
		// Alles op het scherm plaatsen
		RootPanel.get("main").clear();
		RootPanel.get("main").add(flxHeader);
		RootPanel.get("main").add(flxTable);
		RootPanel.get("main").add(flxButton);
	}
	
	/**
	 * Plaatje op de Save button plaatsen, leuke feature.
	 * @param show
	 */
	private void setButtonLoadingImage(boolean show) {
		if (show) {
			btnSubmit.setHTML("Opslaan.. " + element.getImage("Opslaan..", "ajax-loader.gif").toString());
		} else {
			btnSubmit.setHTML("Opslaan " + element.getImage("Opslaan..", "user_add.png").toString());
		}
	}
	
	/**
	 * Functie word gebruikt om invoervelden mbt de Gebruikergroep Student te tonenn of te verbergen.
	 * @param show
	 */
	private void showStudentInvoerVelden(boolean show) {
		lblStudentnummer.setVisible(show);
		txtStudentnummer.setVisible(show);
				
		lblInschrijfjaar.setVisible(show);
		txtInschrijfjaar.setVisible(show);
		
		lblHeeftToegang.setVisible(show);
		chkbxHeeftToegang.setVisible(show);
	}
	
	/**
	 * Laat de faculteit invoervelden zien
	 * @param Boolean show
	 */
	private void showFaculteit(boolean show) {
		lblFaculteit.setVisible(show);
		lstFaculteit.setVisible(show);
	}
	
	/**
	 * Laat het instituut invoerveld zien
	 * @param Boolean show
	 */
	private void showInstituut(boolean show) {
		lblInstituut.setVisible(show);
		lstIstituut.setVisible(show);
	}
	
	/**
	 * Laat de ListBox met opleidingen zien
	 * @param Boolean show
	 */
	private void showOpleiding(boolean show) {
		lblOpleiding.setVisible(show);
		lstOpleiding.setVisible(show);
	}
	
	/**
	 * Laat de ListBox zien waar meerdere opleidingen geselecteerd kunnen worden
	 * @param Boolean show
	 */
	private void showOpleidingSACL(boolean show) {
		lblOpleidingSACL.setVisible(show);
		lstOpleidingSACL.setVisible(show);
	}
	
	/**
	 * Laat de Label en CheckBox zien om de mail mee aan- en uit te zetten.
	 * @param Boolean show
	 */
	private void showMailOntvangen(boolean show) {
		lblMailOntvangen.setVisible(show);
		chkbxMailOntvangen.setVisible(show);
	}
}